/********************************************************************************
 * Copyright (c)2016-2020, ShenZhen WanJiaAn Technology CO.,LTD.
 * All Rights Reserved.
 *
 * File Name     : Qrcode.c
 * Author        : joki.zhu
 * Date          : 2020-01-11
 *
 * Record        :
 * 1.Date        : 2020-01-11
 *   Author      : joki.zhu
 *   Modification: Created file
 ********************************************************************************/
 #ifdef QRCODE_ENABLE
 
#include "Qrcode.h"
#include "zbar.h"
#include "app_common.h"
#include "sample_comm.h"
#include "hi_mw_media_intf.h"
#include "app_common.h"
#include "Audio.h"
#include "IBT_List.h"

typedef struct {
    char *pData;
    int nLen;
    IBTList queue;
}QRCODE_DATA_S;

typedef struct {
    pthread_t pid;
    char bInit;
    char bRun;
    char bLoop;
    IBTListQueue stQueue;
}QRCODE_ATTR_S;

static QRCODE_ATTR_S gs_stQrcodeAttr;

int QrcodePushData(char *pData, int nLen)
{
	QRCODE_DATA_S *pstQrcodeData = NULL;

	pstQrcodeData = (QRCODE_DATA_S *)malloc(sizeof(QRCODE_DATA_S));
	if (pstQrcodeData == NULL) {
		LOGE("malloc failed\n");
		return -1;
	}
	memset(pstQrcodeData, 0, sizeof(QRCODE_DATA_S));

	pstQrcodeData->pData = (char *)malloc(nLen);
	if (pstQrcodeData->pData == NULL) {
		LOGE("malloc failed\n");
		free(pstQrcodeData);
		return -1;
	}
	memcpy(pstQrcodeData->pData, pData, nLen);
	pstQrcodeData->nLen = nLen;

	IBT_List_PushQueueToTail(&gs_stQrcodeAttr.stQueue, &gs_stQrcodeAttr.stQueue.queue, &pstQrcodeData->queue);
	
	//printf("%d %d\n", *pData, nLen);

	return 0;    
}

int QrcodePopData(char **pData, int *pLen)
{
	QRCODE_DATA_S *pstQrcodeData = NULL;
	IBTList *pList = NULL;

	IBT_List_PopQueueFromHead(&gs_stQrcodeAttr.stQueue, &(gs_stQrcodeAttr.stQueue.queue), &pList);
	if (pList == NULL){
		return -1;
	}

	pstQrcodeData = container_of(pList, QRCODE_DATA_S, queue);
	if (pstQrcodeData == NULL) {
		return -1;
	}

	*pData = pstQrcodeData->pData;
	*pLen = pstQrcodeData->nLen;

	free(pstQrcodeData);
	pstQrcodeData = NULL;

	return 0;
}

int QrcodeClearData(void)
{
	int ret = 0;
	char *pData = NULL;
	int len = 0;
	
	while (!IBT_List_IsEmptyQueue(&gs_stQrcodeAttr.stQueue, &gs_stQrcodeAttr.stQueue.queue))
	{
		ret = QrcodePopData(&pData, &len);
		if (ret >= 0) {
			//printf("data: %d len: %d\n", *pData, len);
			free(pData);
			pData = NULL;
		}
	}

	return 0;
}

#if 0
/* solve chinese ssid */
static char *wifi_ssid_conver(char *before, char *bHex)
{
    unsigned int i;
    char *ch1;
    int flag_hex = 0;              
    static char after[32 * 4 + 1];
    
    memset(after, 0, 32 * 4 + 1);
    if (before == NULL || bHex ==NULL) {
        return after;
    }

    /* Whether it is GBK code */
    for (i = 0; i < strlen(before); i++) 
    {
        if (before[i] < 32 || before[i] > 127) {
            flag_hex = 1;
            break;
        }
    }
    ch1 = &after[0];
    if (flag_hex) /* GBK, without '"' */
    {
        *bHex = 1;
        i = 0;
        for (;;) {
            if (before[i] == 0) {
                break;
            }
            if (before[i] < 32 || before[i] > 127) {
                sprintf(ch1, "\\x%02x", (unsigned char)before[i]);
                ch1 += 4;
            } else {
                sprintf(ch1, "%c", (unsigned char)before[i]);
                ch1 += 1;
            }
            i++;
        }
    }
    else /* ASCII SSID, need '"' */
    {
        *bHex = 0;
#ifdef __HuaweiLite__
        strcpy(after, before);
#else
        after[0] ='"';
        strcpy(after+1, before);
        after[strlen(before) + 1] = '"';
#endif /* __HuaweiLite__ */
    }

    return after;
}
#endif

static HI_S32 vpss_scan_qrcode_data(VPSS_GRP VpssGrp, VPSS_CHN VpssChn)
{
	LOGD("grp:%d,chn:%d\n",VpssGrp, VpssChn);
	
    HI_S32 s32ret;
    VIDEO_FRAME_INFO_S stFrame;
    char *pVBufVirt_Y = NULL;
    HI_CHAR *pUserPageAddr[2];
    HI_U32 len = 0;
    VPSS_CHN_ATTR_S stVpssChnAttr;
	zbar_image_scanner_t *scanner = NULL;
	int playInterval = 0;
	
    /* create a reader */
	scanner = zbar_image_scanner_create();
	
    /* configure the reader */
	zbar_image_scanner_set_config(scanner, 0, ZBAR_CFG_ENABLE, 1);

    /* set frame depth */
    memset(&stVpssChnAttr, 0, sizeof(stVpssChnAttr));
    s32ret = HI_MPI_VPSS_GetChnAttr(VpssGrp,VpssChn, &stVpssChnAttr);
    if (HI_SUCCESS != s32ret) {
        LOGE("HI_MPI_VPSS_GetChnAttr err:0x%x\n", s32ret);
        return s32ret;
    }
    //printf("src stVpssChnAttr.u32Depth: %d\n", stVpssChnAttr.u32Depth);
    
    stVpssChnAttr.u32Depth = 3;
    s32ret = HI_MPI_VPSS_SetChnAttr(VpssGrp, VpssChn, &stVpssChnAttr);
    if (HI_SUCCESS != s32ret) {
        LOGE("HI_MPI_VPSS_SetChnAttr err:0x%x\n", s32ret);
        return s32ret;
    }

    ISP_EXPOSURE_ATTR_S stExpAttr;
    HI_U8 u8OriginalCompensation = 0;
    memset(&stExpAttr, 0, sizeof(stExpAttr));
    s32ret = HI_MPI_ISP_GetExposureAttr(0, &stExpAttr);
    if (HI_SUCCESS != s32ret) {
        LOGE("HI_MPI_ISP_GetExposureAttr err:0x%x\n", s32ret);
        return s32ret;
    }
    u8OriginalCompensation = stExpAttr.stAuto.u8Compensation; //src:56
    LOGD("stExpAttr.stAuto.u8Compensation : %d\n", stExpAttr.stAuto.u8Compensation);

    stExpAttr.stAuto.u8Compensation = 36;
    s32ret = HI_MPI_ISP_SetExposureAttr(0, &stExpAttr);
    if (HI_SUCCESS != s32ret) {
        LOGE("HI_MPI_ISP_GetExposureAttr err:0x%x\n", s32ret);
        return s32ret;
    }

    ISP_CSC_ATTR_S stCSCAttr;
    HI_U8 u8OriginalLuma = 0;
    HI_U8 u8OriginalContr = 0;
    memset(&stCSCAttr, 0, sizeof(stCSCAttr));
    s32ret = HI_MPI_ISP_GetCSCAttr(0, &stCSCAttr);
    if (HI_SUCCESS != s32ret) {
        LOGE("HI_MPI_ISP_GetExposureAttr err:0x%x\n", s32ret);
        return s32ret;
    }
    u8OriginalLuma = stCSCAttr.u8Luma;
    u8OriginalContr = stCSCAttr.u8Contr; //src:50
    LOGD("stCSCAttr.u8Contr:%d stCSCAttr.u8Luma:%d\n", stCSCAttr.u8Contr, stCSCAttr.u8Luma);

    stCSCAttr.u8Luma = 20;
    stCSCAttr.u8Contr = 80;
    s32ret = HI_MPI_ISP_SetCSCAttr(0, &stCSCAttr);
    if (HI_SUCCESS != s32ret) {
        LOGE("HI_MPI_ISP_GetExposureAttr err:0x%x\n", s32ret);
        return s32ret;
    }

    while(gs_stQrcodeAttr.bLoop)
   	{
        /* get video frame from vpss chn */
        s32ret = HI_MPI_VPSS_GetChnFrame(VpssGrp, VpssChn, &stFrame, 1000); 
        if (HI_SUCCESS != s32ret) {         
            LOGE("get vpss frame err:0x%x\n", s32ret);
            usleep(10 * 1000);
            continue;
        }
        zbar_image_t *image = zbar_image_create();
        zbar_image_set_format(image, *(int*)"Y800");
        zbar_image_set_size(image, stFrame.stVFrame.u32Width, stFrame.stVFrame.u32Height);
        
        //printf("get vpss frame u32Width:  %d\n", stFrame.stVFrame.u32Width);
        //printf("get vpss frame u32Height: %d\n", stFrame.stVFrame.u32Height);

        len = (stFrame.stVFrame.u32Stride[0])*(stFrame.stVFrame.u32Height)*3 / 2;
        //把YUV映射到内存中
        pUserPageAddr[0] = (HI_CHAR *) HI_MPI_SYS_Mmap(stFrame.stVFrame.u64PhyAddr[0], len);  
        pVBufVirt_Y = pUserPageAddr[0]; 

        //只赋值Y分量数据
        zbar_image_set_data(image,pVBufVirt_Y, (stFrame.stVFrame.u32Stride[0])*(stFrame.stVFrame.u32Height), NULL);

        s32ret= HI_MPI_VPSS_ReleaseChnFrame(VpssGrp, VpssChn, &stFrame);	
        if (HI_SUCCESS != s32ret) {                
            printf("Release vpss frame err:0x%x\n", s32ret); 
            return s32ret;
        }
	  
        /* scan the image for barcodes */
        int n = zbar_scan_image(scanner, image);//二维码扫描
        LOGD("scan qrcode num = %d\n", n);
        if(n==0) {
             HI_MPI_SYS_Munmap(pUserPageAddr[0], len);
             usleep(50 * 1000);
             continue;
        }
                  
        /* extract results */
        const zbar_symbol_t *symbol = zbar_image_first_symbol(image);
        for(; symbol; symbol = zbar_symbol_next(symbol)) 
        {	 
            /* do something useful with results */
            zbar_symbol_type_t typ = zbar_symbol_get_type(symbol);
            const char *data = zbar_symbol_get_data(symbol);
             
            printf("decoded %s symbol \"%s\"\n",
                   zbar_get_symbol_name(typ), data);


#if 0
            char bHex = 0;
            char *pDataStr = NULL;
            pDataStr = wifi_ssid_conver(data, &bHex);
            LOGW("pDataStr ======== %s\n", pDataStr);
#endif
            
            LOGW("scan qrcode success!!!!!!!!!!\n");

            QrcodePushData(data, strlen(data) + 1);
#if 0
            if (playInterval == 0 || playInterval > 100) { //100 * 20 * 1000 = 2s
                while (AudioGetOpsHandle()->play_file_start(AUDIO_RCVWAVE_SUCCESS, AUDIO_TYPE_MP3, 0) < 0) {
                    playInterval = 0;
                    usleep(100 * 1000);
                }
            }
            playInterval++;
#endif
        }

        /* clean up */
        zbar_image_destroy(image);
        
        usleep(20 * 1000);
        HI_MPI_SYS_Munmap(pUserPageAddr[0], len);
   	}

    stVpssChnAttr.u32Depth = 0;
    s32ret = HI_MPI_VPSS_SetChnAttr(VpssGrp, VpssChn, &stVpssChnAttr);
    if (HI_SUCCESS != s32ret) {
        LOGE("HI_MPI_VPSS_SetChnAttr err:0x%x\n", s32ret);
        return s32ret;
    }

    stExpAttr.stAuto.u8Compensation = u8OriginalCompensation;
    s32ret = HI_MPI_ISP_SetExposureAttr(0, &stExpAttr);
    if (HI_SUCCESS != s32ret) {
        LOGE("HI_MPI_ISP_GetExposureAttr err:0x%x\n", s32ret);
        return s32ret;
    }

    stCSCAttr.u8Luma = u8OriginalLuma;
    stCSCAttr.u8Contr = u8OriginalContr;
    s32ret = HI_MPI_ISP_SetCSCAttr(0, &stCSCAttr);
    if (HI_SUCCESS != s32ret) {
        LOGE("HI_MPI_ISP_GetExposureAttr err:0x%x\n", s32ret);
        return s32ret;
    }

    zbar_scanner_destroy(scanner);
   
    return s32ret;			
}


void *tskQrcodeScan(void *args)
{
    SET_THREAD_NAME("tskQrcodeScan");
    pthread_detach(pthread_self());

    VPSS_GRP vpssGrp = 0;
    VPSS_CHN vpssChn = 2;
    vpss_scan_qrcode_data(vpssGrp, vpssChn);
    
    pthread_exit(0);
}

int QrcodeScanStart(void)
{
#ifdef MINI_APP
        return 0;
#endif /* MINI_APP */

    int ret = 0;

    if (gs_stQrcodeAttr.bRun) {
        printf("qrcode scan is running!\n");
        return -1;
    }
    
    gs_stQrcodeAttr.bLoop = 1;
    ret = pthread_create(&gs_stQrcodeAttr.pid, 0, (void *)tskQrcodeScan, NULL);
    if (ret != 0) {
        LOGE("pthread_create tskQrcodeScan failed\n");
        return ret;
    }
    gs_stQrcodeAttr.bRun = 1;

    return 0;
}


int QrcodeScanStop(void)
{
#ifdef MINI_APP
        return 0;
#endif /* MINI_APP */

    if (gs_stQrcodeAttr.bRun) 
    {
        gs_stQrcodeAttr.bLoop = 0;
        usleep(500 * 1000);
        pthread_cancel(gs_stQrcodeAttr.pid);
        gs_stQrcodeAttr.pid = 0;
        gs_stQrcodeAttr.bRun = 0;

    }
    
    return 0;
}

int QrcodeInit(void)
{
#ifdef MINI_APP
        return 0;
#endif /* MINI_APP */

    if (gs_stQrcodeAttr.bInit) {
        printf("qrcode init already Initialized");
        return -1;
    }
    memset(&gs_stQrcodeAttr, 0, sizeof(gs_stQrcodeAttr));
    IBT_List_QueueInit(&gs_stQrcodeAttr.stQueue);
    gs_stQrcodeAttr.bInit = 1;
    
    return 0;
}

int QrcodeDeinit(void)
{
#ifdef MINI_APP
        return 0;
#endif /* MINI_APP */

    if (gs_stQrcodeAttr.bInit)
    {
        IBT_List_QueueDeInit(&gs_stQrcodeAttr.stQueue);
    }

    return 0;
}

#endif /* QRCODE_ENABLE */

